package service

import (
	"database/sql"
	"github.com/jmoiron/sqlx"
	"strconv"
	"sync"
	"zimuzu_cvn_web_api/config"
	"zimuzu_cvn_web_api/lib/grpcClient"
	"zimuzu_cvn_web_api/model"
	. "zimuzu_cvn_web_api/pkg/e"
	"zimuzu_cvn_web_api/pkg/errno"
	"zimuzu_cvn_web_api/pkg/drive/redis"
)

/*
 * @ Author: hupfei
 * @ Description: 获取用户user_amount
 **/
func GetUserAmountByUid(uid int64) (account model.UserAmountDb, err error) {
	account, err = model.GetUserAmount(uid)
	if err != nil {
		if err == sql.ErrNoRows {
			//初始化user_amount
			err = model.InitUserAmount(uid)
			if err != nil {
				return account, errno.DbSearchError
			}
			account, err = model.GetUserAmount(uid)
			if err != nil {
				return account, errno.DbSearchError
			}
			return account, nil
		}
		return account, errno.DbSearchError
	}
	return account, nil
}

/*
 * @ Author: hupfei
 * @ Description: 获取用户cvn_amount
 **/
func GetUserCvnAmountByUid(uid int64) (amount model.CvnAmountDb, err error) {
	amount, err = model.GetCvnAmount(config.C.DB.DB, uid)
	if err != nil {
		if err == sql.ErrNoRows {
			//初始化cvn_amount
			err = InitCvnAmount(uid)
			if err != nil {
				return amount, errno.DbSearchError
			}
			amount, err = model.GetCvnAmount(config.C.DB.DB, uid)
			if err != nil {
				return amount, errno.DbSearchError
			}
			return amount, nil
		}
		return amount, errno.DbSearchError
	}
	return amount, nil
}

/*
 * @ Author: hupfei
 * @ Description: 获取用户usdt_amount
 **/
func GetUserUsdtAmountByUid(uid int64) (amount model.UsdtAmount, err error) {
	amount, err = model.GetUsdtAmountByUid(uid)
	if err != nil {
		if err == sql.ErrNoRows {
			//初始化usdt_amount
			err = InitUsdtAmount(uid)
			if err != nil {
				return amount, errno.DbSearchError
			}
			amount, err = model.GetUsdtAmountByUid(uid)
			if err != nil {
				return amount, errno.DbSearchError
			}
			return amount, nil
		}
		return amount, errno.DbSearchError
	}
	return amount, nil
}

var UpdateSignIng int
var UpdateUsdtSignIng int
var UpdateWalletSignIng int

func InitWalletAddressSign() {
	res ,_ := redis.Get("initdata1")
	intres, _ := strconv.Atoi(res)
	if  intres == 0 {
		return
	}
	if UpdateWalletSignIng != 0 {
		return
	}
	UpdateWalletSignIng = 1
	defer func() {
		UpdateWalletSignIng = 0
	}()

	userArr := make([]model.UserWalletAddressDb, 0)

	err := sqlx.Select(config.C.DB.DB, &userArr, "select * from user_wallet_address where sign_string = '' ")
	if err != nil || len(userArr) == 0 {
		Log("err", err.Error())
		return
	}
	for _, wallet := range userArr {
		AddressCreateData := map[string]string{"uid": strconv.FormatInt(wallet.Uid, 10), "coin_type": wallet.CoinType, "address": wallet.Address}
		AddressCreateResp, err := grpcClient.AddressCreate(AddressCreateData)
		if err != nil {
			Log("err", err.Error())
			return
		}
		//userWalletAddress := model.UserWalletAddressDb{
		//	Uid:         wallet.Uid,
		//	CoinType:    wallet.CoinType,
		//	Address:     wallet.Address,
		//	SignString:  AddressCreateResp.SignString,
		//	SignVersion: AddressCreateResp.SignVersion,
		//}
		_, err = config.C.DB.DB.Exec("update user_wallet_address set sign_string = ?, sign_version = ? where uid = ?", AddressCreateResp.SignString, AddressCreateResp.SignVersion, wallet.Uid)
		if err != nil {
			Log("err", err.Error())
			return
		}
	}
	return
}

func InitCvnAmountSign() {
	res ,_ := redis.Get("initdata2")
	intres, _:= strconv.Atoi(res)
	if  intres == 0 {
		return
	}
	if UpdateSignIng != 0 {
		return
	}
	UpdateSignIng = 1
	defer func() {
		UpdateSignIng = 0
	}()
	var j int
	for i := 0; i < 50000; i++ {
		userArr := make([]model.CvnAmountDb, 0)

		err := sqlx.Select(config.C.DB.DB, &userArr, "select * from cvn_amount where  sign_string = ''  ORDER BY uid LIMIT 500 ")
		if err != nil || len(userArr) == 0 {
			return
		}
		var wg sync.WaitGroup
		wg.Add(len(userArr))
		for _, user := range userArr {
			go func(user model.CvnAmountDb) {
				defer wg.Done()
				var result []model.CvnLogDb
				err = sqlx.Select(config.C.DB.DB, &result, "select id,uid,amount,balance,relate_id,relate_table,`from`,`to`,source,sign_string,sign_version from cvn_log where uid = ? order by id", user.Uid)
				if err != nil || result == nil {
					return
				}
				conn, err := config.C.DB.DB.Beginx()
				for index, cvnLog := range result {
					if cvnLog.SignString != "" {
						continue
					}
					var lastLogSignString, lastLogSignVersion string
					if index > 0 {
						lastLogSignString = result[index-1].SignString
						lastLogSignVersion = result[index-1].SignVersion
					}
					LogCreateRequest := map[string]string{
						"uid":                   strconv.FormatInt(cvnLog.Uid, 10),
						"amount":                strconv.FormatFloat(cvnLog.Amount, 'f', -1, 64),
						"balance":               strconv.FormatFloat(cvnLog.Balance, 'f', -1, 64),
						"relate_id":             cvnLog.RelateId,
						"relate_table":          cvnLog.RelateTable,
						"from":                  cvnLog.From,
						"to":                    cvnLog.To,
						"source":                strconv.Itoa(cvnLog.Source),
						"last_log_sign_string":  lastLogSignString,
						"last_log_sign_version": lastLogSignVersion,
					}
					LogCreateResponse, err := grpcClient.CvnLogCreate(LogCreateRequest)
					if err != nil {
						print(cvnLog.Uid)
						conn.Rollback()
						return
					}
					err = model.UpdateCvnLogSign(conn, cvnLog.Id, LogCreateResponse.SignString, LogCreateResponse.SignVersion)

					result[index].SignString = LogCreateResponse.SignString
					result[index].SignVersion = LogCreateResponse.SignVersion

					if err != nil {
						conn.Rollback()
						return
					}

				}

				lastLogSign, err := model.GetLastCvnLogSign(conn, user.Uid)
				if err != nil && err != sql.ErrNoRows {
					Log("err", err)
					conn.Rollback()
					return
				}
				//生成账户签名， 修改账户金额
				AmountCreateRequest := map[string]string{
					"uid":                   strconv.FormatInt(user.Uid, 10),
					"balance":               strconv.FormatFloat(user.Balance, 'f', -1, 64),
					"frozen_balance":        strconv.FormatFloat(user.FrozenBalance, 'f', -1, 64),
					"last_log_sign_string":  lastLogSign.SignString,
					"last_log_sign_version": lastLogSign.SignVersion,
				}
				AmountCreateResponse, err := grpcClient.CvnAmountCreate(AmountCreateRequest)
				if err != nil {
					conn.Rollback()
					print(user.Uid)
					goto looppp
				} else {
					cvnAmountData := model.UpdateCvnAmountDb{
						Uid:          user.Uid,
						Amount:       0,
						FrozenAmount: 0,
						SignString:   AmountCreateResponse.SignString,
						SignVersion:  AmountCreateResponse.SignVersion,
					}
					err = model.UpdateCvnAmount(config.C.DB.DB, cvnAmountData)
					if err != nil {
						conn.Rollback()
						return
					}
					conn.Commit()
				}
				print(j)
				j++
				return
			looppp:
			}(user)
		}
		wg.Wait()
	}

}

func InitUsdtAmountSign() {
	res ,_ := redis.Get("initdata3")
	intres, _ := strconv.Atoi(res)
	if  intres == 0 {
		return
	}
	if UpdateUsdtSignIng != 0 {
		return
	}
	UpdateUsdtSignIng = 1
	defer func() {
		UpdateUsdtSignIng = 0
	}()
	var j int
	for i := 0; i < 50000; i++ {
		userArr := make([]model.CvnAmountDb, 0)

		err := sqlx.Select(config.C.DB.DB, &userArr, "select * from usdt_amount where sign_string = ''  ORDER BY uid LIMIT 500 ")
		if err != nil || len(userArr) == 0{
			return
		}
		var wg sync.WaitGroup
		wg.Add(len(userArr))
		for _, user := range userArr {
			go func(user model.CvnAmountDb) {
				defer wg.Done()
				var result []model.CvnLogDb
				err = sqlx.Select(config.C.DB.DB, &result, "select id,uid,amount,balance,relate_id,relate_table,`from`,`to`,source,sign_string,sign_version from usdt_log where uid = ? order by id", user.Uid)
				if err != nil {
					if err != nil{
						Log("err", err.Error())
					}

					return
				}
				conn, err := config.C.DB.DB.Beginx()
				for index, cvnLog := range result {
					if cvnLog.SignString != "" {
						continue
					}
					var lastLogSignString, lastLogSignVersion string
					if index > 0 {
						lastLogSignString = result[index-1].SignString
						lastLogSignVersion = result[index-1].SignVersion
					}
					LogCreateRequest := map[string]string{
						"uid":                   strconv.FormatInt(cvnLog.Uid, 10),
						"amount":                strconv.FormatFloat(cvnLog.Amount, 'f', -1, 64),
						"balance":               strconv.FormatFloat(cvnLog.Balance, 'f', -1, 64),
						"relate_id":             cvnLog.RelateId,
						"relate_table":          cvnLog.RelateTable,
						"from":                  cvnLog.From,
						"to":                    cvnLog.To,
						"source":                strconv.Itoa(cvnLog.Source),
						"last_log_sign_string":  lastLogSignString,
						"last_log_sign_version": lastLogSignVersion,
					}
					LogCreateResponse, err := grpcClient.UsdtLogCreate(LogCreateRequest)
					if err != nil {
						print(cvnLog.Uid)
						Log("err", err.Error())
						conn.Rollback()
						return
					}
					err = model.UpdateUsdtLogSign(conn, cvnLog.Id, LogCreateResponse.SignString, LogCreateResponse.SignVersion)

					result[index].SignString = LogCreateResponse.SignString

					if err != nil {
						Log("err", err.Error())
						conn.Rollback()
						return
					}

				}

				lastLogSign, err := model.GetLastUsdtLogSign(conn, user.Uid)
				if err != nil && err != sql.ErrNoRows {
					Log("err", err.Error())
					conn.Rollback()
					return
				}
				//生成账户签名， 修改账户金额
				AmountCreateRequest := map[string]string{
					"uid":                   strconv.FormatInt(user.Uid, 10),
					"balance":               strconv.FormatFloat(user.Balance, 'f', -1, 64),
					"frozen_balance":        strconv.FormatFloat(user.FrozenBalance, 'f', -1, 64),
					"last_log_sign_string":  lastLogSign.SignString,
					"last_log_sign_version": lastLogSign.SignVersion,
				}
				AmountCreateResponse, err := grpcClient.UsdtAmountCreate(AmountCreateRequest)
				if err != nil {
					conn.Rollback()
					Log("err", err.Error())
					print(user.Uid)
					goto looppp
				} else {
					cvnAmountData := model.UpdateUsdtAmountDb{
						Uid:          user.Uid,
						Amount:       0,
						FrozenAmount: 0,
						SignString:   AmountCreateResponse.SignString,
						SignVersion:  AmountCreateResponse.SignVersion,
					}
					err = model.UpdateUsdtAmount(config.C.DB.DB, cvnAmountData)
					if err != nil {
						Log("err", err.Error())
						conn.Rollback()
						return
					}
					conn.Commit()
				}
				print(j)
				j++
				return
			looppp:
			}(user)
		}
		wg.Wait()
	}

}

func InitSingleCvnAmount(uid int64) {
	var user model.CvnAmountDb
	err := sqlx.Get(config.C.DB.DB, &user, "select * from cvn_amount where uid = ?", uid)
	if err != nil && err != sql.ErrNoRows {
		return
	}
	var result []model.CvnLogDb
	err = sqlx.Select(config.C.DB.DB, &result, "select id,uid,amount,balance,relate_id,relate_table,`from`,`to`,source,sign_string,sign_version from cvn_log where uid = ? order by id", user.Uid)
	if err != nil || result == nil {
		return
	}
	conn, err := config.C.DB.DB.Beginx()
	for index, cvnLog := range result {
		//if cvnLog.SignString != "" {
		//	continue
		//}
		var lastLogSignString, lastLogSignVersion string
		if index > 0 {
			lastLogSignString = result[index-1].SignString
			lastLogSignVersion = result[index-1].SignVersion
		}
		LogCreateRequest := map[string]string{
			"uid":                   strconv.FormatInt(cvnLog.Uid, 10),
			"amount":                strconv.FormatFloat(cvnLog.Amount, 'f', -1, 64),
			"balance":               strconv.FormatFloat(cvnLog.Balance, 'f', -1, 64),
			"relate_id":             cvnLog.RelateId,
			"relate_table":          cvnLog.RelateTable,
			"from":                  cvnLog.From,
			"to":                    cvnLog.To,
			"source":                strconv.Itoa(cvnLog.Source),
			"last_log_sign_string":  lastLogSignString,
			"last_log_sign_version": lastLogSignVersion,
		}
		LogCreateResponse, err := grpcClient.CvnLogCreate(LogCreateRequest)
		if err != nil {
			print(cvnLog.Uid)
			conn.Rollback()
			return
		}
		err = model.UpdateCvnLogSign(conn, cvnLog.Id, LogCreateResponse.SignString, LogCreateResponse.SignVersion)

		result[index].SignString = LogCreateResponse.SignString
		result[index].SignVersion = LogCreateResponse.SignVersion

		if err != nil {
			conn.Rollback()
			return
		}

	}

	lastLogSign, err := model.GetLastCvnLogSign(conn, user.Uid)
	if err != nil && err != sql.ErrNoRows {
		Log("err", err)
		conn.Rollback()
		return
	}
	//生成账户签名， 修改账户金额
	AmountCreateRequest := map[string]string{
		"uid":                   strconv.FormatInt(user.Uid, 10),
		"balance":               strconv.FormatFloat(user.Balance, 'f', -1, 64),
		"frozen_balance":        strconv.FormatFloat(user.FrozenBalance, 'f', -1, 64),
		"last_log_sign_string":  lastLogSign.SignString,
		"last_log_sign_version": lastLogSign.SignVersion,
	}
	AmountCreateResponse, err := grpcClient.CvnAmountCreate(AmountCreateRequest)
	if err != nil {
		conn.Rollback()
		print(user.Uid)
	} else {
		cvnAmountData := model.UpdateCvnAmountDb{
			Uid:          user.Uid,
			Amount:       0,
			FrozenAmount: 0,
			SignString:   AmountCreateResponse.SignString,
			SignVersion:  AmountCreateResponse.SignVersion,
		}
		err = model.UpdateCvnAmount(config.C.DB.DB, cvnAmountData)
		if err != nil {
			conn.Rollback()
			return
		}
		conn.Commit()
	}

	return
}

func InitSingleUsdtAmount(uid int64) {
	var user model.UsdtAmount
	err := sqlx.Get(config.C.DB.DB, &user, "select * from usdt_amount where uid = ?", uid)
	if err != nil && err != sql.ErrNoRows {
		return
	}
	var result []model.UsdtLogDB
	err = sqlx.Select(config.C.DB.DB, &result, "select id,uid,amount,balance,relate_id,relate_table,`from`,`to`,source,sign_string,sign_version from usdt_log where uid = ? order by id", user.Uid)
	if err != nil || result == nil {
		return
	}
	conn, err := config.C.DB.DB.Beginx()
	for index, cvnLog := range result {
		//if cvnLog.SignString != "" {
		//	continue
		//}
		var lastLogSignString, lastLogSignVersion string
		if index > 0 {
			lastLogSignString = result[index-1].SignString
			lastLogSignVersion = result[index-1].SignVersion
		}
		LogCreateRequest := map[string]string{
			"uid":                   strconv.FormatInt(cvnLog.Uid, 10),
			"amount":                strconv.FormatFloat(cvnLog.Amount, 'f', -1, 64),
			"balance":               strconv.FormatFloat(cvnLog.Balance, 'f', -1, 64),
			"relate_id":             cvnLog.RelateId,
			"relate_table":          cvnLog.RelateTable,
			"from":                  cvnLog.From,
			"to":                    cvnLog.To,
			"source":                strconv.Itoa(cvnLog.Source),
			"last_log_sign_string":  lastLogSignString,
			"last_log_sign_version": lastLogSignVersion,
		}
		LogCreateResponse, err := grpcClient.UsdtLogCreate(LogCreateRequest)
		if err != nil {
			print(cvnLog.Uid)
			conn.Rollback()
			return
		}
		err = model.UpdateUsdtLogSign(conn, cvnLog.Id, LogCreateResponse.SignString, LogCreateResponse.SignVersion)

		result[index].SignString = LogCreateResponse.SignString
		result[index].SignVersion = LogCreateResponse.SignVersion

		if err != nil {
			conn.Rollback()
			return
		}

	}

	lastLogSign, err := model.GetLastUsdtLogSign(conn, user.Uid)
	if err != nil && err != sql.ErrNoRows {
		Log("err", err)
		conn.Rollback()
		return
	}
	//生成账户签名， 修改账户金额
	AmountCreateRequest := map[string]string{
		"uid":                   strconv.FormatInt(user.Uid, 10),
		"balance":               strconv.FormatFloat(user.Balance, 'f', -1, 64),
		"frozen_balance":        strconv.FormatFloat(user.FrozenBalance, 'f', -1, 64),
		"last_log_sign_string":  lastLogSign.SignString,
		"last_log_sign_version": lastLogSign.SignVersion,
	}
	AmountCreateResponse, err := grpcClient.UsdtLogCreate(AmountCreateRequest)
	if err != nil {
		conn.Rollback()
		print(user.Uid)
	} else {
		cvnAmountData := model.UpdateUsdtAmountDb{
			Uid:          user.Uid,
			Amount:       0,
			FrozenAmount: 0,
			SignString:   AmountCreateResponse.SignString,
			SignVersion:  AmountCreateResponse.SignVersion,
		}
		err = model.UpdateUsdtAmount(config.C.DB.DB, cvnAmountData)
		if err != nil {
			conn.Rollback()
			return
		}
		conn.Commit()
	}

	return
}
